package com.prj.ufdm.demo.tutorial.j2se;

import java.net.URL;

/**
 * DESC: 获取类加载器
 * 类加载器分为 <br>
 * @author 胡义振
 * @date 2020年5月8日
 */
public class ClassLoaderTest {
	
	public static void main(String[] args) {
		bootStrapClassLoader();
	}

	/**
     * DESC: 启动（Bootstrap）类加载器
	 * 启动类加载器主要加载的是JVM自身需要的类，这个类加载使用C++语言实现的，是虚拟机自身的一部分，
	 * 它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中
	 * 注意必由于虚拟机是按照文件名识别加载jar包的，如rt.jar，如果文件名不被虚拟机识别，即使把jar包丢到lib目录下也是没有作用的
	 * (出于安全考虑，Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类)。
	 * @auther 胡义振
	 * @date 2020年5月8日 
	 * @return
	 */
	public static void bootStrapClassLoader() {
		URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
		for (URL url : urLs) {
		    System.out.println(url.toExternalForm());
		}
		
		ClassLoader bootStrapClassLoader = java.lang.String.class.getClassLoader();
		// 可知由于BootstrapClassLoader对Java不可见,所以返回了null，我们也可以通过某一个类的加载器是否为null来作为判断该类是不是使用BootstrapClassLoader进行加载的依据
		System.out.println(bootStrapClassLoader);
	}
	
	
	/**
	 * DESC: 扩展（extClassLoader）类加载器
	 * 主要负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有jar包
	 * 或者由java.ext.dirs系统属性指定的jar包.放入这个目录下的jar包对AppClassLoader加载器都是可见的
	 *  (因为ExtClassLoader是AppClassLoader的父加载器,并且Java类加载器采用了委托机制).
	 * @auther 胡义振
	 * @date 2020年5月8日 
	 * @return
	 */
	public static void extClassLoader() {
		
		String extDirs = System.getProperty("java.ext.dirs");
		for (String path : extDirs.split(";")) {
		    System.out.println(path);
		}
		
		// sun.security.ec.ECKeyFactory 这个类是 \jre\lib\ext\sunec.jar 包中
		ClassLoader extClassLoader = sun.security.ec.ECKeyFactory.class.getClassLoader();
		// ExtClassLoader的父加载器为null,由于BootstrapClassLoader对Java不可见,所以返回了null
		System.out.println(extClassLoader);
		System.out.println(extClassLoader.getParent());
	}
	
	/**
	 * DESC: 应用（AppClassLoader）类加载器或称系统类加载器
	 * 负责在JVM启动时,加载来自在命令java中的classpath或者java.class.path系统属性
	 * 或者CLASSPATH操作系统属性所指定的JAR类包和类路径.
	 * @auther 胡义振
	 * @date 2020年5月8日 
	 * @return
	 */
	public static void appClassLoader() {
		
		String classPath = System.getProperty("java.class.path");
		for (String path : classPath.split(";")) {
		    System.out.println(path);
		}
		
		// 获取 AppClassLoader ，用于加载 Classpath 的类
		ClassLoader appClassLoader = ClassLoaderTest.class.getClassLoader();
		
		// AppClassLoader的父加载器是ExtClassLoader
		System.out.println(appClassLoader);
		System.out.println(appClassLoader.getParent());
	}
}
